/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

// extra comment. If you can read this then project updated correctly from internet
// comment back into server
package Main;

import javax.microedition.midlet.*;
import javax.microedition.lcdui.*;

/**
 * @author alwynster
 */
public class PowerPongMIDlet extends MIDlet implements CommandListener {
    
    static int timer = 0;

    private boolean midletPaused = false;

    static Bluetooth bt;
    static Accelerometer acc;
    static Menu_Graphics menu;
    static Game_Graphics gfx;       //<editor-fold defaultstate="collapsed" desc="Getter">
    public static Game_Graphics GetGameGraphics() { return gfx; }
    //</editor-fold>
    private Command clientCommand, serverCommand, accCommand;
    private boolean inquiryActive = false;

    static Thread gameThread;
    final static int fps = 20;

    static int width = 0, height = 0;      //<editor-fold defaultstate="collapsed" desc="Size getters">
    public static int GetWidth() { return width; } public static int GetHeight() { return height; }
    public static void SetWidth(int newWidth) { width = newWidth; } public static void SetHeight(int newHeight) { height = newHeight; }
    //</editor-fold>
    
    public static Display disp;
    
    final static int CLIENT = 1, SINGLE = 0, SERVER = 2;
    static int mode = 0;
   /**
    * The PowerPongMIDlet constructor.
    */
   public PowerPongMIDlet() {
   }
   
   public static void setMenuTitle(String str) { menu.setTitle(str); }
           
   
   public static Thread getGameThread() { return gameThread; }
   
   public static int getMode() { return mode; }
   public static void setMode(int newMode) 
   {
       mode = newMode; 
       switch(mode)
       {
           case SERVER:
               gfx.setTitle("Server");
               break;
           case CLIENT:
               acc.EnableAccelerometer();
               gfx.setTitle("Client");
               // reverse ball velocity
//               gfx.ball.setVelocityX(-gfx.ball.getVelocityX());
//               gfx.ball.setX(1 - gfx.ball.getX());
               break;
       }
   }
   
   public static Form getMainForm()
   {
       return form;
   }

   public static void createServer()
   {
        gfx.resetGame();
        timer = fps;
        bt.InitBluetooth();
        bt.CreateServer();
   }
   
   public static void createClient()
   {
        gfx.resetGame();
        bt.InitBluetooth();
        bt.FindServer(null);
   }
   
   public static void createSingle()
   {
        gfx.resetGame();
        showDisplayable(gfx);
        acc.EnableAccelerometer();
        startGameThread();
        
   }
   
   //<editor-fold defaultstate="collapsed" desc=" Generated Method: commandAction for Displayables ">//GEN-BEGIN:|7-commandAction|0|7-preCommandAction
   /**
    * Called by a system to indicated that a command has been invoked on a particular displayable.
    * @param command the Command that was invoked
    * @param displayable the Displayable where the command was invoked
    */
   public void commandAction(Command command, Displayable displayable) {//GEN-END:|7-commandAction|0|7-preCommandAction
       // write pre-action user code here
       if (displayable == form) {//GEN-BEGIN:|7-commandAction|1|19-preAction
           if (command == exitCommand) {//GEN-END:|7-commandAction|1|19-preAction
               // write pre-action user code here
               exitMIDlet();//GEN-LINE:|7-commandAction|2|19-postAction
               // write post-action user code here
            }
            else if(command == serverCommand)
            {
                gfx.resetGame();
                timer = fps;
                bt.InitBluetooth();
                bt.CreateServer();
//                showDisplayable(gfx);
//                acc.EnableAccelerometer();
//                startGameThread();
            }
            else if(command == clientCommand)
            {
            }
            else if (command == accCommand)
            {
                gfx.resetGame();
                showDisplayable(gfx);
                acc.EnableAccelerometer();
                startGameThread();
            }//GEN-BEGIN:|7-commandAction|3|7-postCommandAction
       }//GEN-END:|7-commandAction|3|7-postCommandAction
       // write post-action user code here
   }//GEN-BEGIN:|7-commandAction|4|
   //</editor-fold>//GEN-END:|7-commandAction|4|

   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: exitCommand ">//GEN-BEGIN:|18-getter|0|18-preInit
   /**
    * Returns an initiliazed instance of exitCommand component.
    * @return the initialized component instance
    */
   public Command getExitCommand() {
       if (exitCommand == null) {//GEN-END:|18-getter|0|18-preInit
           // write pre-init user code here
           exitCommand = new Command("Exit", Command.EXIT, 0);//GEN-LINE:|18-getter|1|18-postInit
           // write post-init user code here
       }//GEN-BEGIN:|18-getter|2|
       return exitCommand;
   }
   //</editor-fold>//GEN-END:|18-getter|2|

   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: clientCommand ">
   /**
    * Returns an initiliazed instance of clientCommand component.
    * @return the initialized component instance
    */
   public Command getClientCommand() {
       if (clientCommand == null) {
           // write pre-init user code here
           clientCommand = new Command("Client", Command.ITEM, 0);
           // write post-init user code here
       }
       return clientCommand;
   }
   //</editor-fold>
   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: accCommand ">
   /**
    * Returns an initialized instance of clientCommand component.
    * @return the initialized component instance
    */
   public Command getAccCommand() {
       if (accCommand == null) {
           // write pre-init user code here
           accCommand = new Command("Accelerometer", Command.ITEM, 0);
           // write post-init user code here
       }
       return accCommand;
   }
   //</editor-fold>
   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: serverCommand ">
   /**
    * Returns an initiliazed instance of serverCommand component.
    * @return the initialized component instance
    */
   public Command getServerCommand() {
       if (serverCommand == null) {
           // write pre-init user code here
           serverCommand = new Command("server", Command.ITEM, 0);
           // write post-init user code here
       }
       return serverCommand;
   }
   //</editor-fold>

   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: form ">//GEN-BEGIN:|14-getter|0|14-preInit
   /**
    * Returns an initiliazed instance of form component.
    * @return the initialized component instance
    */
   public Form getForm() {
       if (form == null) {//GEN-END:|14-getter|0|14-preInit
           // write pre-init user code here
           form = new Form("Welcome", new Item[] { getStringItem() });//GEN-BEGIN:|14-getter|1|14-postInit
           form.addCommand(getExitCommand());
           form.setCommandListener(this);//GEN-END:|14-getter|1|14-postInit
           form.addCommand(getAccCommand());
           form.addCommand(getClientCommand());
           form.addCommand(getServerCommand());
           // write post-init user code here
       }//GEN-BEGIN:|14-getter|2|
       return form;
   }
   //</editor-fold>//GEN-END:|14-getter|2|

   //<editor-fold defaultstate="collapsed" desc=" Generated Getter: stringItem ">//GEN-BEGIN:|16-getter|0|16-preInit
   /**
    * Returns an initiliazed instance of stringItem component.
    * @return the initialized component instance
    */
   public StringItem getStringItem() {
       if (stringItem == null) {//GEN-END:|16-getter|0|16-preInit
           // write pre-init user code here
           stringItem = new StringItem("Hello", "Hello, World!");//GEN-LINE:|16-getter|1|16-postInit
           // write post-init user code here
       }//GEN-BEGIN:|16-getter|2|
       return stringItem;
   }
   //</editor-fold>//GEN-END:|16-getter|2|

   //<editor-fold defaultstate="collapsed" desc=" Generated Fields ">
   private Command exitCommand;
   private static Form form;
   private StringItem stringItem;
   //</editor-fold>

   //<editor-fold defaultstate="collapsed" desc=" Generated Methods ">//GEN-BEGIN:|methods|0|
   //</editor-fold>//GEN-END:|methods|0|

   //<editor-fold defaultstate="collapsed" desc=" Generated Method: initialize ">//GEN-BEGIN:|0-initialize|0|0-preInitialize
   /**
    * Initializes the application.
    * It is called only once when the MIDlet is started. The method is called before the <code>startMIDlet</code> method.
    */
   private void initialize() {//GEN-END:|0-initialize|0|0-preInitialize
        // write pre-initialize user code here
//GEN-LINE:|0-initialize|1|0-postInitialize
        // write post-initialize user code here
   }//GEN-BEGIN:|0-initialize|2|
   //</editor-fold>//GEN-END:|0-initialize|2|

   static boolean running = true;
   public static void stopGameThread() { running = false; gameThread = null; }
   
   public static void startGameThread()
   {
       running = true;
       if(gameThread == null)
           gameThread = GameThread();
       gameThread.start();
   }

   //<editor-fold defaultstate="collapsed" desc=" Generated Method: startMIDlet ">//GEN-BEGIN:|3-startMIDlet|0|3-preAction
   /**
    * Performs an action assigned to the Mobile Device - MIDlet Started point.
    */
   public void startMIDlet() {//GEN-END:|3-startMIDlet|0|3-preAction
        // write pre-action user code here
//       switchDisplayable(null, getForm());
       disp = Display.getDisplay(this);
       UpdateSize();

        bt = new Bluetooth();
//        form.append(bt.getStringItem());
//        bt.InitBluetooth();

        // Create main physics thread
        gameThread = GameThread();

        try {
            menu = new Menu_Graphics(0x0000FF);
            menu.setTitle("creating menu");
            showDisplayable(menu);
        } catch (Exception e) {
            menu.setTitle("Cannot create menu graphics");
        }

        try {
            menu.setTitle("creating gfx");
            gfx = new Game_Graphics();
        } catch (Exception e) {
            menu.setTitle("Cannot create game graphics");
        }

        try {
            menu.setTitle("creating acc");
            acc = new Accelerometer();
//            menu.append(acc.accString);
        } catch (Exception e) {
            showAlert("Error", "Cannot create accelerometer", 2500);
        }

        try {
            menu.setTitle("creating fm");
            FileManager.OpenSettingsFile();
        } catch (Exception ex) {
            menu.setTitle("Cannot create file manager");
        }


        if(FileManager.GetSize() > 0)
        {
            String acc_range = "";
            try {
                acc_range = FileManager.ReadSettings(1);
//                stringItem.setText(acc_range);
                acc.setMin(Double.parseDouble(acc_range.substring(0, acc_range.indexOf(";"))));
                acc.setMax(Double.parseDouble(acc_range.substring(acc_range.indexOf(";") + 1)));
            } catch (Exception ex) {
                showAlert("Error", "Acc data: " + acc_range, 1500);
            }
        }

        menu.setTitle("Power Pong"); 
        menu.repaint();
        // write post-action user code here
   }//GEN-BEGIN:|3-startMIDlet|2|
   //</editor-fold>//GEN-END:|3-startMIDlet|2|

   private static Thread GameThread()
   {
       return new Thread() //<editor-fold defaultstate="collapsed" desc="Main thread stuff">
        {
            public void run() {
                while(running)
                {
                    long startTime;
                    try {
                        startTime = System.currentTimeMillis();
                        if(mode == SINGLE)
                            gfx.AI(); //AI makes velocity decisions of opponents paddle
                        gfx.move(); //moves everything that is on the screan
                        if(mode == SERVER || mode == SINGLE) 
                            gfx.generate(); //generates weapons
                        gfx.repaint();               
                        if(mode == SERVER && bt.IsConnected() && timer == 0)
                        {
                            timer = fps;
//                            bt.SendString("S " + gfx.GetPlayer().getY());
//                            bt.SendString("BX" + gfx.getBall().getX());
//                            bt.SendString("BY" + gfx.getBall().getY());
                            bt.SendString("S1" + gfx.GetPlayer().getScore() + "."); 
                            bt.SendString("S2" + gfx.GetOpponent().getScore() + "."); 
//                            bt.SendString("P " + gfx.GetOpponent().getY());
//                            bt.SendString("paint");
                        }
                        else
                            timer--;
                        Thread.sleep(1000 / fps - (System.currentTimeMillis() - startTime)); // set to 25 fps
                    } catch (Exception ex) { 
                    }
                }
            }
        };
        //</editor-fold>
   }
   
   //<editor-fold defaultstate="collapsed" desc=" Generated Method: resumeMIDlet ">//GEN-BEGIN:|4-resumeMIDlet|0|4-preAction
   /**
    * Performs an action assigned to the Mobile Device - MIDlet Resumed point.
    */
   public void resumeMIDlet() {//GEN-END:|4-resumeMIDlet|0|4-preAction
        // write pre-action user code here
//GEN-LINE:|4-resumeMIDlet|1|4-postAction
        // write post-action user code here
   }//GEN-BEGIN:|4-resumeMIDlet|2|
   //</editor-fold>//GEN-END:|4-resumeMIDlet|2|

   //<editor-fold defaultstate="collapsed" desc=" Generated Method: switchDisplayable ">
   /**
    * Switches a current displayable in a display. The <code>display</code> instance is taken from <code>getDisplay</code> method. This method is used by all actions in the design for switching displayable.
    * @param alert the Alert which is temporarily set to the display; if <code>null</code>, then <code>nextDisplayable</code> is set immediately
    * @param nextDisplayable the Displayable to be set
    */
   public static void switchDisplayable(Alert alert, Displayable nextDisplayable) {
        // write pre-switch user code here
       Display display = disp;
       if (alert == null) {
           display.setCurrent(nextDisplayable);
       } else {
           try
           {
               display.setCurrent(alert, nextDisplayable);
           }
           catch(Exception e)
           {
               menu.setTitle(alert.getString());
           }
       }                                             
        // write post-switch user code here
   }                                   
   //</editor-fold>

   /**
    * Returns a display instance.
    * @return the display instance.
    */
   public Display getDisplay() {
      return Display.getDisplay(this);
   }

   /**
    * Exits MIDlet.
    */
   public void exitMIDlet()
   {
        FileManager.WriteSettings(acc.getMin() + ";" + acc.getMax(), 1);
        menu.setTitle(FileManager.ReadSettings(1));
        FileManager.CloseSettingsFile();
//
        switchDisplayable(null, null);
        destroyApp(true);
        notifyDestroyed();
   }

   /**
    * Called when MIDlet is started.
    * Checks whether the MIDlet have been already started and initialize/starts or resumes the MIDlet.
    */
   public void startApp() {
      if (midletPaused) {
         resumeMIDlet();
      } else {
         initialize();
         startMIDlet();
      }
      midletPaused = false;
   }

   /**
    * Called when MIDlet is paused.
    */
   public void pauseApp() {
      midletPaused = true;
   }

   /**
    * Called to signal the MIDlet to terminate.
    * @param unconditional if true, then the MIDlet has to be unconditionally terminated and all resources has to be released.
    */
   public void destroyApp(boolean unconditional) {
   }

   /*
    * Print output to main debug screen
    */
   public void DebugPrint(String newString)
   {
       stringItem.setText(newString);
   }

   static Displayable oldScreen;
   static void showDisplayable(Displayable displayable)
   {
       oldScreen = disp.getCurrent();
       switchDisplayable(null, displayable);
   }

   static Alert oldAlert;
   static void showAlert(String title, String text, int to)
   {
        Alert alrt = new Alert(title, text, null, AlertType.INFO);
        alrt.setTimeout(to);

        switchDisplayable(alrt, disp.getCurrent());
   }

//   static void revertDisplayable()
//   {
//       switchDisplayable(null, oldScreen);
//   }

   static void UpdateSize()
   {
       try {
           width = disp.getCurrent().getWidth();           
           height = disp.getCurrent().getHeight();
       } catch (Exception e) {
       }
   }
   
    class Menu_Graphics extends Canvas implements CommandListener
    {
        Button_Manager button_man;
        Command cancelCommand, exitCommand;
        int background = 0;

        public Menu_Graphics(int backColour)
        {
            background = backColour;
            
            button_man = new Button_Manager(this.getWidth(), this.getHeight(), 3);
            Main.PowerPongMIDlet.SetWidth(this.getWidth());
            Main.PowerPongMIDlet.SetHeight(this.getHeight());
            // add player buttons:
            String[] names = {"/Main/Buttons/single_button.jpg","/Main/Buttons/server_button.jpg","/Main/Buttons/client_button.jpg"};
            String[] names2 = {"/Main/Buttons/single_button2.jpg","/Main/Buttons/server_button2.jpg","/Main/Buttons/client_button2.jpg"};
            button_man.addButtons(names, names2, 0.5, 0.5, true, (int) (Main.PowerPongMIDlet.GetWidth() / 1.5));// , UP, GAME_B);
            // set button actions:
            button_man.setButton(1, Button_Manager.single_player);
            button_man.setButton(2, Button_Manager.multi_server);
            button_man.setButton(3, Button_Manager.multi_client);

    //        this.setTitle("Accelerometer Test");

            this.addCommand(getExitCommand());
            this.setCommandListener(this);
        }

        //<editor-fold defaultstate="collapsed" desc=" Generated Getter: getCancelCommand ">
        /**
         * Returns an initialized instance of cancelCommand component.
         * @return the initialized component instance
         */
        private Command getCancelCommand() {
           if (cancelCommand == null) {
                // write pre-init user code here
              cancelCommand = new Command("Cancel", Command.CANCEL, 0);
                // write post-init user code here
           }
           return cancelCommand;
        }
        //</editor-fold>

       //<editor-fold defaultstate="collapsed" desc=" Generated Getter: exitCommand ">                                   
       /**
        * Returns an initialized instance of exitCommand component.
        * @return the initialized component instance
        */
       public Command getExitCommand() {
           if (exitCommand == null) {                                 
               // write pre-init user code here
               exitCommand = new Command("Exit", Command.EXIT, 0);                                   
               // write post-init user code here
           }                         
           return exitCommand;
       }
       //</editor-fold>                       

       Font scoresFont = Font.getFont(Font.FACE_MONOSPACE, Font.STYLE_BOLD, Font.SIZE_LARGE); 
       // paint debugging game
       protected void paint(Graphics g)
       {
           g.setColor(background);
           g.fillRect(0, 0, this.getWidth(), this.getHeight()); //back drop
            try {
                button_man.DrawButtons(g);
            } catch (Exception ex) {
                ex.printStackTrace();
            }
       }

       //<editor-fold defaultstate="collapsed" desc="Relay touch screen presses">
       int pointerX, pointerY;
       /**
        * Called when the pointer is pressed.
        */
       protected void pointerPressed(int x, int y) {
           button_man.ButtonPress(x,y);
       }

       /**
        * Called when the pointer is released.
        */
       protected void pointerReleased(int x, int y)
       {
           button_man.ButtonRelease(x,y);
       }
       //</editor-fold>

       // command button pressed
       public void commandAction(Command c, Displayable d) {
            if (c == exitCommand) {   
                exitMIDlet();
            }
            else if(c == cancelCommand)
            {
                Main.PowerPongMIDlet.showDisplayable(Main.PowerPongMIDlet.getMainForm());
                Main.PowerPongMIDlet.bt.SendString("stop");
    //            Main.PowerPongMIDlet.revertDisplayable();
            }
       }

        //resize the picture to zoom in or out the picture
        private Image createThumbnail(Image image,int width)
        {
           int sourceWidth = image.getWidth();
           int sourceHeight = image.getHeight();
           int thumbWidth = width;
           int thumbHeight = -1;

           if (thumbHeight == -1)
              thumbHeight = thumbWidth * sourceHeight / sourceWidth;

           Image thumb = Image.createImage(thumbWidth, thumbHeight);
           Graphics g = thumb.getGraphics();

           for (int y = 0; y < thumbHeight; y++)
           {
              for (int x = 0; x < thumbWidth; x++)
              {
                g.setClip(x, y, 1, 1);
                int dx = x * sourceWidth / thumbWidth;
                int dy = y * sourceHeight / thumbHeight;
                g.drawImage(image, x - dx, y - dy, Graphics.LEFT | Graphics.TOP);
              }
           }

           Image immutableThumb = Image.createImage(thumb);

           return immutableThumb;
        }
    }
}
